package com.ys.util.wanli;


import com.ys.util.ApiHttpUtils;
import com.ys.vo.R;
import org.springframework.http.HttpHeaders;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class WanliUtils {

    /**
     * name and value separator
     */
    private static final String NAME_VALUE_SEPARATOR = "=";

    /**
     * comma
     */
    private static final String COMMA = ",";

    /**
     * algorithm
     */
    private static final String ALGORITHM = "algorithm";

    /**
     * signature
     */
    private static final String SIGNATURE = "signature";

    /**
     * keyVersion
     */
    private static final String KEY_VERSION = "keyVersion";

    /**
     * RSA256
     */
    private static final String RSA_256 = "RSA256";


    //测试客户私钥
//    private static final String signPrivateKey =  "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCIEzAK38UDs2VJfTHShhrGACBsnLrUrky6+zEE2btC87Mo1wLXuTGhWHXuCXWMqZm345VpbLPPHGDU/UoG0m90hZG+3ztcPfW5hF7vkXo1NaLQ6RzqYnROAdhplfbl659aIgPNH6uzKiVovcX4g1+he8hvKA/xgb/DF1iqyxGJSrnjqPa+UgiCZj0ukHIQnBBwsTNompzDWWl+iiA4sFr+ilFWfkVq9VojnyAcypYJxz0siiGurLDJl6G/ptX/WHRxnUw3/uecIXVLXqIBmovVOqCj5EwoPMnbO9HIxKX43xldyZZUNqWt5pXj6aLytkEGigniYSZcQUocgHT34AvBAgMBAAECggEAJKe2i1dYBPUwVamJ4EILuEaUdW2KznvdY4kC3WGhlhl7q4av11ily+a+bc7SgX+2TtjZiLqlfScR1o4cgNXy/Bp29km//csbBExqHnK7ztWR9GC3T1QSLGlG2Lpy9eCQ3oDHMVxUrkCuLxbf21/YRPHJPlg2Y0ImW/FQC0IEiUzZUr5Owg7zNzDYcyjt1A0I9w2GCxgaZDxxoNE/AwD5cp0dc3+LT/QKdIVY/hxQZ3BlE541pk5LsLQN5639DyivQx4LouTTu5LaYOdd9EW/f/9YxUOnYwBA2A1Yd/OVJhyuAI8fV31hp+vFNlcRKnGQg5I69L24E+LKUmOuC/d4AQKBgQC8rNzleFiSyxgT/oKUk7RNjvBnbmP2ADiWeAsAxWo+nmDcrSj1QxJ/SdQ5r30An0onaZ3R2kD1Oz7t4s/H+yFNhA6/ZEWe8zAxYqGBIgCoNpDPgY382eF5CJpea9zXSKxv5XuIlFbtpNh1HBBEp2uUKjSx9448fcEzn/SogMeCIQKBgQC4oWJzHtrm/toojLIAczTGkFZuSs7GIyuk3XI4L3BF6ZCdV57SPJpYGhe7twk3+bBEE8pyvZjcFOtMaqk4kxyUh3N6+ixw/uy2cPbqs/yOlv6bgC5kyXmf/lzh7a6vxtJnJ1Cxvxv/TZ/CYLbVjp+jEhAqi0+NTPwvHvxgumqVoQKBgBDyujkGsXYmNjh9kT9FcVnSMDgqS2JqrKqfh+V+1kdftLW9/ELjzoKOoDi6UdE/fcrCiwGxyEn/E20NBbsiDODIrwZ0PGjF0ZtuD7Ho2wRBOorZSWbgL4fOxQccS08vYQYAKDOhl5lrSGJkrfVs0JYToH4oDafTaAp6IOEOCF3hAoGBAI5AWZgVB9e+N9vSOzs5iEoM32ru3E2wv2mw7NX5Rum2wSNZZRbadpi20d5hcgrcqEBrdynchq/atkgUTfk272hIzGLN6fvNjhgrBTNkJYy/LcAljJk+2iS5WFsCQ/tOlsG/et7YPfwAlLyww23bC4ga3LXKzCo0TIEJwK3OM1zBAoGBAICf031sETlA3ICd1oynfFuLDIp7erRxZgWmh2fgASY1a98LR7nvm4F7XgUHeinILIiHLrdaQtS439DydEC8wf2Q+GlcQqyv048He+8vgjNoz7CP9kqYyIex567K/MJTrRkh3KHMSyX1oaSXrgvW4/6SYvCX2hlxXeOnLJie6LVe";
    //正式客户私钥
    private static final String signPrivateKey =  "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCRnNhM4nnj8M3vddAY5WILGuZGKoqYiQdefzmrG2OiM84xl/72vnWthOokre+QGpT9NN0qgOb7gki+aAilrGQGdkHG6i9yr/je1leu15hmFaMvhG8JVjtsotaIBJZvtcrS8GPzHO/3MT6/LhyOnNX8lxlDabQv9lhvIr9LDFI6ulbbBMp1hRGEfsDrbtZveKEaMGpP9kkGOKv5yvFf3fVjrKQr7/DQ/EjeUMlDJ9TBc0fYvXrk4TdD4otgZ6HOCa2rs0gLM9GdWC1hWPA544gHoQM2IoNrO23q4Zd3QaVzt/3UZp/P1O1n9AjzUbyYmveCl/HPWKQsmXrqLLftXn2NAgMBAAECggEBAIdLYVqGr9SP4PiW0cTgFOnWk5EsY9x4raUqtw16BGgolHRWEut2aebQ8bEk/8s4N6jQ3pJodLXKBwcLqMUu2T170YAeBfoc8TMzmwL0hUCM6DP1bCoTumElKAn3oUOoeQznmSbBg2F9mxyNnrEPnm/0gN+3LlnGHcMdWPpFN34iS/mWAr28MfvilvaU8OE8bm95TtqPDOLLt51hiPmANQJTTs5fnc8pq125aJGOuJ9jbsnJ2lEADnAJmwuIMXCREUho0QN63+XTy77EVyMhdLwYdD9AWRtYGUyfy77wrIZqblKWubZIsFLluIXkPiZJjJo3uO4+nI73F9Pio09SS0ECgYEA4aysUIS0Kl/GBTVqZdGKG4j+ntkkEw6/8qJx7+s+1JNSEMtAU/p4Jq/aROKxol0n/tJUU/MPaCMbc3s1vohJxYAMd8m28wsxGdae8nUEVGrOQdQQJehFlnSVRLIjCjC2ViZ1aSLFgdp9HBJClUWd+0pMrV5C6p5K5mK6KO0JBd0CgYEApS4APUj55wVshaQzZuRg4ghOV+pGQBllZnYUOJIzasdL/s5oKt/PNC6JDlFJtEKRj2emFw3CJ8ia4w2t5460k9e+8GQDJHca0rzTjXaJ5qzh0kn75adyYY4heT863mE3n8NYV83jac4wzJoKVvmxyo7SQ7Kf2v0XLfMB4BpJk3ECgYA6BNu0Q7nSHxdY5Xe6P5njJGBZ1Hea0rL0nWDvjqpzmoCBws+CB6X2REW4ahPDK3IJ6Gc3wgiW/FelY+rYVk+pEBekgF6hs6HnA6+PpBf94AuxDuUr6cBiQwzRQX8Ssp1eHrsW0ZK3pMV/fw5RNDm+jkaSV+aaTSHygzVbKj2knQKBgHIdIZU1QVBU8vAwzEIdLMF7M4SRGQ9XfDIZCUc72cG/BcV3G4fjLubB73WwutaJ1r3XwWrT2npZoIeT/7ylXiN1PTgeH/2lOyazxQNKDWMLtMbuzdOOpvq2knGNOUJAr4j0D6g5WQ7Tn+r50ILd5fImUSTr1nwXtVfNNlJ4VrRBAoGBANoimCQmmUCMofdgh+PCrcBlmWKrLteIS8Gv3vE5e2xuGt43EjAI3C+ovc62jWszDYMWZQ4DVwft7GsUNtrr3CIvMAdTDfOt9VMX1VjRb2uuiphSUHGTqXYkFuSIBaQKWzSWItWtNW5byQFChcY07BoNJZc8z7OKUdCgckJRyWEa";

    //测试客户公钥
//    private static final String verifyPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiBMwCt/FA7NlSX0x0oYaxgAgbJy61K5MuvsxBNm7QvOzKNcC17kxoVh17gl1jKmZt+OVaWyzzxxg1P1KBtJvdIWRvt87XD31uYRe75F6NTWi0Okc6mJ0TgHYaZX25eufWiIDzR+rsyolaL3F+INfoXvIbygP8YG/wxdYqssRiUq546j2vlIIgmY9LpByEJwQcLEzaJqcw1lpfoogOLBa/opRVn5FavVaI58gHMqWCcc9LIohrqywyZehv6bV/1h0cZ1MN/7nnCF1S16iAZqL1Tqgo+RMKDzJ2zvRyMSl+N8ZXcmWVDalreaV4+mi8rZBBooJ4mEmXEFKHIB09+ALwQIDAQAB";
    //正式客户公钥
    private static final String verifyPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkZzYTOJ54/DN73XQGOViCxrmRiqKmIkHXn85qxtjojPOMZf+9r51rYTqJK3vkBqU/TTdKoDm+4JIvmgIpaxkBnZBxuovcq/43tZXrteYZhWjL4RvCVY7bKLWiASWb7XK0vBj8xzv9zE+vy4cjpzV/JcZQ2m0L/ZYbyK/SwxSOrpW2wTKdYURhH7A627Wb3ihGjBqT/ZJBjir+crxX931Y6ykK+/w0PxI3lDJQyfUwXNH2L165OE3Q+KLYGehzgmtq7NICzPRnVgtYVjwOeOIB6EDNiKDaztt6uGXd0Glc7f91Gafz9TtZ/QI81G8mJr3gpfxz1ikLJl66iy37V59jQIDAQAB";

    //测试万里汇公钥
//    private static final String alipayKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmVT7qqmcSBsw0yOjYRN4qe76gJkE+LOoZYBkTz89oUJKMB9Gh4a+PLkBkcNzsp77FSnryXSv3xHgpvAfm1Z+25BA1jivKfN+81z6ECRh6Iw64pOky88/vOYo2NHwZ3woOtQmwSs155oIpfiulGwEA/Nb0fwT7nKm8Ir6UC3+jHIyNQqowLo+LAafoPP+lHAkkduSnm4iasJAF/buM82InhCvSpywz9qMjMOcfRUsVTPyzh+9pQHkDFGgE7UqD3vJfANdq54dZllghp5PEnG3/k2x1nYgERCjBIHwTbTsaQfZ0kDAH7VWYCatccf8KYUzVS1J5ug/1nhLUs6xdKK+2QIDAQAB";
    //正式万里汇公钥
    private static final String alipayKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnJ/OoL+WbrBcHL7tpjg1b50xUmoDMzfm89tGq5fB949YrZDuHPE15LDz746/+GHThROT9FhuaBTXAnQWJWRvcjYDdzLPxE8ceD80LrSpDJOrbt3bID5qAQYKYb8TQX0xuGYteaDH0dpWo+j3fyOCSQPV4d/WD99jaYgGgsTqs2AyhDGe0nnR+gHnGdh3DGpA/jcthTXe7wcw24t7AibelAdMdNDZNYCC2VdWNszDwTmtkpQ8E77cA2dqvkl72+O5+jGW2HNScI0w05r/yltHw+3gu6JY2JhY+VHCc1hCRK+kG4PsEgXWVTTA8pWNC0bORE+Eyp85yGNGYSQqugIOrQIDAQAB";

    public static String result(String content,String httpMethod,String uriWithQueryString,String clientId,String connectedCustomerId){
        String result = "";
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
            Date now = new Date();
            String timeString = sdf.format(now);

            String signature = sign(httpMethod, uriWithQueryString, clientId, timeString, content, signPrivateKey);

            String signatureHeaderPayload = ALGORITHM +
                    NAME_VALUE_SEPARATOR +
                    RSA_256 +
                    COMMA +
                    KEY_VERSION +
                    NAME_VALUE_SEPARATOR +
                    "2" +
                    COMMA +
                    SIGNATURE +
                    NAME_VALUE_SEPARATOR +
                    signature;
            System.out.println("signatureHeaderPayload:\n" + signatureHeaderPayload);

            boolean res = verify(httpMethod, uriWithQueryString, clientId, timeString, content, signature, verifyPublicKey);
            if (res) {
                System.out.println("verify success.");
            }


            Map<String, String> paramsHerder = new HashMap<String, String>();
            paramsHerder.put("Client-Id", clientId);
            paramsHerder.put("Signature", signatureHeaderPayload);
            paramsHerder.put("Content-Type", "application/json");
            paramsHerder.put("Request-Time", timeString);
            if (!connectedCustomerId.equals("")){
                paramsHerder.put("Connected-CustomerId", connectedCustomerId);
            }
            //测试网关地址
//            String serverURL = "https://open-sitprod-sg.alipay.com";
            //正式网关地址
            String serverURL = "https://open-sea.worldfirst.com";
            result = ApiHttpUtils.sendPostBody(serverURL + uriWithQueryString,
                    content, paramsHerder);
        }catch (Exception e) {
            return e.getMessage();
        }
        return result;

    }

    public static HttpHeaders responseWanli(String content, String httpMethod, String uriWithQueryString, String clientId, String connectedCustomerId){
        HttpHeaders httpHeaders = new HttpHeaders();
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
            Date now = new Date();
            String timeString = sdf.format(now);

            String signature = sign(httpMethod, uriWithQueryString, clientId, timeString, content, signPrivateKey);

            String signatureHeaderPayload = ALGORITHM +
                    NAME_VALUE_SEPARATOR +
                    RSA_256 +
                    COMMA +
                    KEY_VERSION +
                    NAME_VALUE_SEPARATOR +
                    "2" +
                    COMMA +
                    SIGNATURE +
                    NAME_VALUE_SEPARATOR +
                    signature;
            System.out.println("signatureHeaderPayload:\n" + signatureHeaderPayload);

            boolean res = verify(httpMethod, uriWithQueryString, clientId, timeString, content, signature, verifyPublicKey);
            if (res) {
                System.out.println("verify success.");
            }


            httpHeaders.set("Client-Id", clientId);
            httpHeaders.set("Signature", signatureHeaderPayload);
            httpHeaders.set("Content-Type", "application/json");
            httpHeaders.set("Response-Time", timeString);
            if (!connectedCustomerId.equals("")){
                httpHeaders.set("Connected-CustomerId", connectedCustomerId);
            }
        }catch (Exception e) {
            return httpHeaders;
        }
        return httpHeaders;
    }

    /**
     * Sign the contents of the merchant request
     *
     * @param httpMethod         http method                e.g., POST, GET
     * @param uriWithQueryString query string in url        e.g., if your request url is https://{domain_name}.com/ams/api/pay/query uriWithQueryString should be /ams/api/pay/query not https://{domain_name}.com/ams/api/pay/query
     * @param clientId           clientId issued by WorldFirst  e.g., *****
     * @param timeString         "request-time" in request  e.g., 2020-01-03T14:36:27+08:00
     * @param reqBody            json format request        e.g., "{"paymentRequestId":"*****","refundRequestId":"*****","refundAmount":{"currency":"USD","value":"123"},"extendInfo":{"":""}}"
     * @param merchantPrivateKey your private key
     */
    public static String sign(
            String httpMethod,
            String uriWithQueryString,
            String clientId,
            String timeString,
            String reqBody,
            String merchantPrivateKey) throws Exception {
        // 1. construct the request content
        String reqContent = httpMethod + " " + uriWithQueryString + "\n" + clientId + "." + timeString + "." + reqBody;
        System.out.println("reqContent is " + "\n" + reqContent);

        // 2. sign with your private key
        String originalString = signWithSHA256RSA(reqContent, merchantPrivateKey);
        //  System.out.println("originalString is " + originalString);

        // 4. return the encoded String
        return URLEncoder.encode(originalString, "UTF-8");
    }

    /**
     * Check the response of WorldFirst
     *
     * @param httpMethod         http method                  e.g., POST, GET
     * @param uriWithQueryString query string in url          e.g., if your request url is https://{domain_name}.com/ams/api/pay/query uriWithQueryString should be /ams/api/pay/query not https://{domain_name}.com/ams/api/pay/query
     * @param clientId           clientId issued by WorldFirst    e.g., *****
     * @param timeString         "response-time" in response  e.g., 2020-01-02T22:36:32-08:00
     * @param rspBody            json format response         e.g., "{"acquirerId":"xxx","refundAmount":{"currency":"CNY","value":"123"},"refundFromAmount":{"currency":"JPY","value":"234"},"refundId":"xxx","refundTime":"2020-01-03T14:36:32+08:00","result":{"resultCode":"SUCCESS","resultMessage":"success","resultStatus":"S"}}"
     * @param worldfirstPublicKey    public key from WorldFirst
     */
    public static boolean verify(
            String httpMethod,
            String uriWithQueryString,
            String clientId,
            String timeString,
            String rspBody,
            String signature,
            String worldfirstPublicKey) throws Exception {
        // 1. construct the response content
        String responseContent = httpMethod + " " + uriWithQueryString + "\n" + clientId + "." + timeString + "." + rspBody;

        // 2. decode the signature string
        String decodedString = URLDecoder.decode(signature, "UTF-8");

        // 3. verify the response with WorldFirst's public key
        return verifySignatureWithSHA256RSA(responseContent, decodedString, worldfirstPublicKey);

    }


    /**
     * Generate base64 encoded signature using the sender's private key
     *
     * @param reqContent:    the original content to be signed by the sender
     * @param strPrivateKey: the private key which should be base64 encoded
     */
    private static String signWithSHA256RSA(String reqContent, String strPrivateKey) throws Exception {
        Signature privateSignature = Signature.getInstance("SHA256withRSA");
        privateSignature.initSign(getPrivateKeyFromBase64String(strPrivateKey));
        privateSignature.update(reqContent.getBytes(StandardCharsets.UTF_8));
        byte[] bytes = privateSignature.sign();

        return Base64.getEncoder().encodeToString(bytes);
    }


    private static PrivateKey getPrivateKeyFromBase64String(String privateKeyString) throws Exception {
        byte[] b1 = Base64.getDecoder().decode(privateKeyString);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(b1);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePrivate(spec);
    }

    /**
     * Verify if the received signature is correctly generated with the sender's public key
     *
     * @param rspContent: the original content signed by the sender and to be verified by the receiver.
     * @param signature:  the signature generated by the sender
     * @param strPk:      the public key string-base64 encoded
     */
    private static boolean verifySignatureWithSHA256RSA(String rspContent, String signature, String strPk) throws Exception {
        PublicKey publicKey = getPublicKeyFromBase64String(strPk);

        Signature publicSignature = Signature.getInstance("SHA256withRSA");
        publicSignature.initVerify(publicKey);
        publicSignature.update(rspContent.getBytes(StandardCharsets.UTF_8));

        byte[] signatureBytes = Base64.getDecoder().decode(signature);
        return publicSignature.verify(signatureBytes);
    }


    private static PublicKey getPublicKeyFromBase64String(String publicKeyString) throws Exception {
        byte[] b1 = Base64.getDecoder().decode(publicKeyString);
        X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(b1);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(X509publicKey);
    }

    /**
     * 回调验签
     */
    public static boolean verifyHdYq(
            String httpMethod,
            String uriWithQueryString,
            String clientId,
            String timeString,
            String contentYq,
            String signature) throws Exception {
        boolean res = verify(httpMethod, uriWithQueryString, clientId, timeString, contentYq, signature, alipayKey);
        if (res) {
            System.out.println("verify success.");
        }
        return res;

    }
}